

/*Ryan Schaeffer, Ryan Ott
  Final Project*/

#include <stdlib.h>
#include <stdio.h>
#include "lexer.h"
#include <assert.h>

/*Parses the first token of each line*/
int vm_parseinstruction (struct vm_Instruction *inst, struct list *ll){
	struct token t = token_popfront(ll);
	if(t.type != OPCODE){
		fprintf(stderr, "OPCODE expected as first instruction");
		return 0;
	}

	if(t.v.op ==MOVE)
		return vm_parseMOV(inst,ll);
	else if(t.v.op==ADD)
		return vm_parseADD(inst,ll);
	else if(t.v.op==SWAP)
		return vm_parseSWAP(inst,ll);
	else if(t.v.op==CLR)
		return vm_parseCLR(inst, ll);
	else if(t.v.op==JZ)
		return vm_parseJZ(inst,ll);
	else if(t.v.op==JNZ) 
		return vm_parseJNZ(inst, ll);
	else if(t.v.op==SUB)
		return vm_parseSUB(inst,ll);
	else if(t.v.op==MULT)
		return vm_parseMULT(inst,ll);
	else if(t.v.op==DIV)
		return vm_parseDIV(inst,ll);
	else if(t.v.op==GET)
		return vm_parseGET(inst,ll);
	else if(t.v.op==PUT)
		return vm_parsePUT(inst,ll);
	return 0;

}

/*implements the MOV Ra x instruction */
int vm_MOV_Ra_x (struct vm_State *vm, union value a, union value b) {
        vm->regs[(int) a.r]=b.i;

        return 0;
}
/*implements the MOV Ra Rb instruction */
int vm_MOV_Ra_Rb (struct vm_State *vm, union value a, union value b) {
        vm->regs [(int) a.r] = vm->regs [(int) b.r];

        return 0;
}
	
/*Moves second(integer or registe) to first(register)*/
int vm_parseMOV (struct vm_Instruction *inst, struct list *ll) {

        
	struct token dest= token_popfront(ll);
        struct token source = token_popfront(ll);

        inst->a = dest.v;
        inst->b = source.v;

        if (dest.type != REGZ) {
                fprintf (stderr,  "expected REGISTER for first argument to MOV\n");
                return -1;
        }

	if (source.type == REGZ)
                inst->fxn = vm_MOV_Ra_Rb;
        else if (source.type == INTEGER)
                inst->fxn = vm_MOV_Ra_x;
        else {
                fprintf (stderr, "expected INTEGER or REGISTER for second argument to MOV\n");
                return -1;
        }

        return 0;
}

/*implements SWAP function*/
int vm_SWAP (struct vm_State *vm, union value a, union value b) {
	int temp = vm->regs [(int) a.r];
	vm->regs [(int) a.r] = vm->regs [(int) b.r];
	vm->regs [(int) b.r] = temp;
	
	return 0;
}

/*Swaps second(register) with first(register)*/
int vm_parseSWAP(struct vm_Instruction *inst, struct list *ll) {
	struct token first = token_popfront(ll);
	struct token second = token_popfront(ll);

	inst->a = first.v;
	inst->b = second.v;

	if ((first.type == REGZ) && (second.type == REGZ))
		inst->fxn = vm_SWAP;
	else {
		fprintf(stderr, "expected REGISTER as first and second argument to SWAP\n");
		return -1;
	}

	return 0;
}

/*implements CLR function*/
int vm_CLR (struct vm_State *vm, union value a, union value b) {
	vm->regs [(int) a.r] = 0;
	
	return 0;
}


/*Parses token in clear function*/
int vm_parseCLR(struct vm_Instruction *inst, struct list *ll) {
	struct token reg = token_popfront (ll);
	
	inst->a = reg.v;
	inst->b = reg.v;

	if (reg.type == REGZ)
		inst->fxn = vm_CLR;
	else {
		fprintf (stderr, "expected REGISTER as argument to CLR\n");
                return -1;
	}
	
	return 0;
}

/*implements Jump if zero function*/
int vm_JZ (struct vm_State *vm, union value a, union value b) {
	if (vm->regs[(int) a.r] == 0)
		return b.i;
	else
		return 0;
}

/*If register is 0, Jump to line number*/
int vm_parseJZ(struct vm_Instruction *inst, struct list *ll) {
	struct token rg = token_popfront (ll);
	struct token ln = token_popfront (ll);

	inst->a = rg.v;
	inst->b = ln.v;

	if (rg.type != REGZ) {
		fprintf(stderr, "expected REGISTER as first argument to JZ\n");
		return -1;
	}

	inst->fxn = vm_JZ;

	return 0;
}

/*implements Jump if not zero function*/
int vm_JNZ (struct vm_State *vm, union value a, union value b) {
	if (vm->regs[(int) a.r] != 0) 
		return b.i;
	
	else
		return 0;
}


/*If register is not 0, Jump to line number*/
int vm_parseJNZ(struct vm_Instruction *inst, struct list *ll) {
	struct token rg = token_popfront (ll);
	struct token ln = token_popfront (ll);

	inst->a = rg.v;
	inst->b = ln.v;

	if (rg.type != REGZ) {
		fprintf(stderr, "expected REGISTER as first argument to JZ\n");
		return -1;
	}

	inst->fxn = vm_JNZ;

	return 0;
}

/*implements addition of two registers*/
int vm_ADD_Ra_Rb (struct vm_State *vm, union value a, union value b) {
	vm->regs [(int) a.r] = ((vm->regs [(int) b.r]) + (vm->regs [(int) a.r]));
	
	return 0;
}

/*implements addition of int to register*/
int vm_ADD_Ra_x (struct vm_State *vm, union value a, union value b) {
	vm->regs [(int) a.r] = ((vm->regs [(int) a.r]) + b.i);

	return 0;

}

/*Adds second(register or integer) to first(register)*/
int vm_parseADD(struct vm_Instruction *inst, struct list *ll) {
	struct token first = token_popfront (ll);
	struct token second = token_popfront (ll);
	
	inst->a = first.v;
	inst->b = second.v;

	if (first.type != REGZ) {
		fprintf(stderr, "expected REGISTER as first argument to ADD\n");
		return -1;	
	}
	
	if (second.type == REGZ)
		inst->fxn = vm_ADD_Ra_Rb;
	else if (second.type == INTEGER)
		inst->fxn = vm_ADD_Ra_x;
	else {
		fprintf(stderr, "expected REGISTER or INTEGER as second argument to ADD\n");
		return -1;
	}

	return 0;
}

/*implements subtraction of two registers*/
int vm_SUB_Ra_Rb (struct vm_State *vm, union value a, union value b) {
        vm->regs [(int) a.r] = (vm->regs [(int) a.r]) - (vm->regs [(int) b.r]);
	return 0;
}

/*implements subtraction of int from a register*/
int vm_SUB_Ra_x (struct vm_State *vm, union value a, union value b) {
	vm->regs [(int) a.r] = ((vm->regs [(int) a.r]) - b.i);

	return 0;
}

/*Subtracts second(register or integer) from first (register)*/	
int vm_parseSUB(struct vm_Instruction *inst, struct list *ll) {
        struct token first = token_popfront (ll);
        struct token second = token_popfront (ll);

	inst->a = first.v;
        inst->b = second.v;
  
	if (first.type != REGZ) {
                fprintf(stderr, "expected REGISTER as first argument to SUB\n");
                return -1;
        }

        if (second.type == REGZ)
                inst->fxn = vm_SUB_Ra_Rb;
        else if (second.type == INTEGER)
                inst->fxn = vm_SUB_Ra_x;
        else {
                fprintf(stderr, "expected REGISTER or INTEGER as second argument to SUB\n");
                return -1;
        }

        return 0;
}

/*implements multiplication of two registers*/
int vm_MULT_Ra_Rb (struct vm_State *vm, union value a, union value b) {
         vm->regs [(int) a.r] = ((vm->regs [(int) a.r]) * (vm->regs [(int) b.r]));

        return 0;
}

/*implements multiplication of int from a register*/
int vm_MULT_Ra_x (struct vm_State *vm, union value a, union value b) {
         vm->regs [(int) a.r] = ((vm->regs [(int) a.r]) * b.i);

        return 0;
}

/*Multiplies second(register or integer) by first(register)*/
int vm_parseMULT(struct vm_Instruction *inst, struct list *ll) {
        struct token first = token_popfront (ll);
        struct token second = token_popfront (ll);
 
        inst->a = first.v;
        inst->b = second.v;

        if (first.type != REGZ) {
                fprintf(stderr, "expected REGISTER as first argument to MULT\n");
                return -1;
        }

        if (second.type == REGZ)
                inst->fxn = vm_MULT_Ra_Rb;
        else if (second.type == INTEGER)
                inst->fxn = vm_MULT_Ra_x;
        else {
                fprintf(stderr, "expected REGISTER or INTEGER as second argument to MULT\n");
                return -1;
        }

        return 0;
}

/*implements division of two register*/
int vm_DIV_Ra_Rb (struct vm_State *vm, union value a, union value b) {
         vm->regs [(int) a.r] = ((vm->regs [(int) a.r]) / (vm->regs [(int) b.r]));

        return 0;
}

/*implements division of int from a register*/
int vm_DIV_Ra_x (struct vm_State *vm, union value a, union value b) {
         vm->regs [(int) a.r] = ((vm->regs [(int)a.r]) / (b.i));

        return 0;
}

/*Divide second(register or integer) into first(register)*/
int vm_parseDIV(struct vm_Instruction *inst, struct list *ll) {
        struct token first = token_popfront (ll);
        struct token second = token_popfront (ll);

        inst->a = first.v;
        inst->b = second.v;

        if (first.type != REGZ) {
                fprintf(stderr, "expected REGISTER as first argument to DIV\n");
                return -1;
        }

        if (second.type == REGZ)
                inst->fxn = vm_DIV_Ra_Rb;
        else if (second.type == INTEGER)
                inst->fxn = vm_DIV_Ra_x;
        else {
                fprintf(stderr, "expected REGISTER or INTEGER as second argument to DIV\n");
                return -1;
        }

        return 0;
}

/*implements output function*/
int vm_GET (struct vm_State *vm, union value a, union value b) {
	int k;
	fprintf(stderr, "INPUT: ");
	fscanf(stdin, "%d", &k);
	vm->regs [(int) a.r] =k;
	return 0; 
}


/*Gets value from input and stores in register*/
int vm_parseGET(struct vm_Instruction *inst, struct list *ll) {
	struct token rg = token_popfront (ll);
	
	inst->a = rg.v;
	inst->b = rg.v;

	if (rg.type != REGZ) {
		fprintf(stderr, "expected REGISTER as argument to GET\n");
		return -1;
	}
	
	else 
		inst->fxn = vm_GET;
	
	return 0;
}

/*implements input function*/
int vm_PUT (struct vm_State *vm, union value a, union value b) {
        fprintf(stderr, "%d\n", vm->regs[(int) a.r]);
        return 0;
}

/*Prints contents of register*/
int vm_parsePUT(struct vm_Instruction *inst, struct list *ll) {
	struct token rg = token_popfront (ll);
	
	inst->a = rg.v;
	inst->b = rg.v; 
	
	if (rg.type != REGZ) {
		fprintf(stderr, "expected REGISTER as argument to PUT\n");
		return -1;
	}

	else
		inst->fxn = vm_PUT;

	return 0;

}

int main(int argc, char *argv []){
	
	struct vm_State vm;
	int k;
	FILE *fp;

	if (argc != 2) {
		fprintf (stderr, "you need to specify a file name!!"); 	//Gets arguments of input
	}

	fp = fopen (argv [1], "r");

	for(k=0; k<=7; ++k)		//Sets all registers to 0
		vm.regs[k]=0;
	
	struct list *ll=lex(fp,stdout,stderr);		//Create linked list of tokens
	int ln=token_popfront(ll).v.i;			//determines number of instructions		
	struct vm_Instruction *instructs=malloc(sizeof(struct vm_Instruction) * ln);
	int i,j;

	for(i=0;i<ln;i++)		//creates an array of the instructions
		vm_parseinstruction(&instructs[i],ll);
	
	vm.IP=0;
	for(vm.IP=0; vm.IP<ln; ++vm.IP) {		//Loop through array of instruction	
		

		j=(*instructs[vm.IP].fxn)(&vm, instructs[vm.IP].a, instructs[vm.IP].b);		//takes care of jumps
		if(j>0){
			vm.IP=j-2;
		}
	}
	
	//frees stuff
	free(instructs);	
	delete_list(ll);			
	fclose(fp);
}
